课程主页:http://www.cs.cmu.edu/afs/cs/academic/class/15213-f15/www/schedule.html

课程资料:https://github.com/EugeneLiu/translationCSAPP

课程视频:https://www.bilibili.com/video/av31289365/

这一讲的主题是浮点数。

背景:小数二进制数

二进制小数

转换成十进制的结果为

例子

表示
$5\frac 3 4$ $101.11_2$
$2\frac 7 8$ $10.111_2$
$1\frac{7 }{16}$ $1.0111_2$

不难得到如下结果

  • 右移(无符号)相当于除以$2$
  • 左移(无符号)相当于乘以$2$
  • $0.111111 \ldots _2$比$1.0$略小,因为
    • $1 / 2+1 / 4+1 / 8+\ldots+1 / 2^{i}+\ldots \rightarrow 1.0$
    • 表示为$1.0-\epsilon$

表示数字

利用二进制表示小数有一些限制。

  • 限制1
    • 有限位只能表示形如$x / 2^{k}$的数
    • 例如$\frac 1 3$需要无限位表示:$0.0101010101[01]_{\ldots 2}$
  • 限制2
    • 表示的范围有限,无法表示非常大或者非常小的数字

IEEE浮点标准:定义

浮点数表示

  • 数值形式:

    • 符号位$s$确定数字是负数还是正数
    • 尾数$M$为属于范围$1\sim 2-\epsilon$或$0\sim 1-\epsilon$的二进制小数
    • 阶码$E$是指数
  • 编码

    • 最高位s表示符号位$s$
    • 阶码字段exp表示$E$
    • 小数字段frac表示$M$

根据阶码字段的不同,浮点数可以分为以下几个部分:

下面分别介绍:

规格化的值

  • 当$\text{exp}\neq 000\ldots 0$且$\text{exp}\neq 111\ldots 1$称为规格化的值
  • 阶码的值为$E=\exp -\text{bias}$
    • 其中$\exp$为exp域的无符号值
    • $\text {bias}=2^{k-1}-1$,其中$k$为exp域的比特数
  • 小数字段隐式的用$1$作为首位:$M=1 .\text{xxx} \ldots \text{x}_{2}$
    • $\text{xxx} \ldots \text{x}$:小数域
    • 取最小值当$\text{frac}=000\ldots 0(M=1.0)$
    • 取最大值当$\text{frac}=111\ldots 1(M=2.0-\epsilon)$

来看一个具体例子:

  • 浮点数$F=15213.0$

  • 尾数:

  • 阶码:

  • 结果:

非规格化的值

此时

  • 当$\text{exp}=000\ldots 0$称为非规格化的值
  • 阶码为$E=1-\text {bias }$
  • 小数字段的首位为$0$,即$M=0 .\text{xxx} \ldots \text{x}_{2}$
  • 例子
    • $\exp =000 \ldots 0, \text {frac}=000 \ldots 0$
      • 上述两者均表示$0$
      • 注意根据符号位的不同有$+0$和$-0$的区别
    • $\exp =000 \ldots 0, \text {frac}\neq000 \ldots 0$
      • 可以表示接近于$0.0$的数

特殊值

  • 当$\text{exp}=111\ldots 1$称为特殊值
  • 例1:$\exp =111 \ldots 11, \text {frac}=000 \ldots 0$
    • 表示$\infty$
    • 表示操作溢出,$s=1$表示$-\infty$,$s=0$表示$+ \infty$
    • $1.0 / 0.0=-1.0 /-0.0=+\infty, 1.0 /-0.0=-\infty$
  • 例2:$\exp =111 \ldots 01, \text {frac}\neq000 \ldots 0$
    • Not-­a-­Number(NaN)
    • 表示计算结果无法表达的情形
    • 例如$\text{sqrt}(-1),\infty-\infty,\infty \times 0$

可视化:浮点编码

例子和性质

考虑8比特的浮点数表示:

浮点数和对应编码的关系如下:

从上表中不难看出,如果将浮点数的二进制表达视为无符号整数,则上述表达是升序的,这也是IEEE设计这种表达的原因(只考虑正数部分)。

不难发现越接近于$0$的部分浮点数越密集:

IEEE编码的特殊性质

  • 浮点数零与整型数零的表达式相同
    • 所有比特都为$0$
  • (几乎)可以使用无符号整数比较
    • 必须首先比较符号位
    • 必须考虑$-0=0$
    • NaN有问题
      • 比其他值大
      • 比较的结果是什么?
    • 其他部分没问题
      • 非规格化 vs 规格化
      • 规格化 vs 无穷

舍入,加法,乘法

浮点数运行的基本想法

  • $\mathrm{x}+_\mathrm{f} \mathrm{y}=\operatorname{Round}(\mathrm{x}+\mathrm{y})$
  • $\mathrm{x}\times_\mathrm{f} \mathrm{y}=\operatorname{Round}(\mathrm{x}\times\mathrm{y})$
  • 基本想法
    • 首先计算精确结果
    • 使它适合所需的精度
      • 如果指数太大可能会溢出
      • 可能将其舍入为frac

舍入

考虑几种舍入的方法:

浮点数采用的是向偶数舍入。

向偶数舍入

  • 默认舍入模式

    • 其他的舍入模式会产生偏差:一组正数之和将一致地被高估或低估
  • 应用于小数位/比特位

    • 当位于中间值时,进行舍入,使得最低有效位为偶数

    • 例子

      | 值 | 舍入 | 原因 |
      | ————- | —— | ———————————- |
      | 7.8949999 | 7.89 | (Less than half way) |
      | 7.8950001 | 7.90 | (Greater than half way) |
      | 7.8950000 | 7.90 | (Greater than half way) |
      | 7.8850000 | 7.88 | (Half way-round down) |

舍入二进制数

  • 二进制小数

    • 如果最低有效位为$0$则表示偶数
    • 中间值表示为$100\ldots_2$
  • 例子

    • 舍入到小数点后$2$比特

      | 值 | 二进制 | 舍入 | 动作 | 舍入后的值 |
      | ———————- | —————— | ————- | ———————————- | —————— |
      | $2\frac 3 {32}$ | $10.00011_2$ | $10.00_2$ | $(<1 / 2-\text {down})$ | $2$ | | $2\frac 3 {16}$ | $10.00110_2$ | $10.01_2$ | $(>1 / 2-\text{up})$ | $2\frac 14$ |
      | $2\frac 7 {8}$ | $10.11100_2$ | $11.00_2$ | $(1 / 2-\text{up})$ | $3$ |
      | $2\frac 5 {8}$ | $10.10100_2$ | $10.10_2$ | $(1 / 2-\text{down})$ | $2\frac 1 2$ |

浮点数乘法

  • 考虑$(-1)^{s_1} M_1 2^{E_1} \times(-1)^{s_2} M_2 2^{E_2}$
  • 精确结果:$(-1)^sM2^E$
    • 符号位$s$:$s_1 \text{^} s_2$
    • 尾数$M$:$M_1\times M_2$
    • 阶码$E$:$E_1+E_2$
  • 修正
    • 如果$M\ge 2$,右移$M$,增加$E$
    • 如果$E$超过范围,则溢出
    • 舍入$M$以满足frac的精度

浮点数乘法的数学性质

  • 与交换环比较
    • 在乘法运算下封闭?是的
      • 但可能会产生无穷大或NaN
    • 可交换的?是的
    • 可结合? 不是
      • 四舍五入的溢出和不精确
      • $(1 e 20 1 e 20) 1 e-20=\inf , 1 e 20 (1 e 20 1 e-20)=1 e 20$
    • $1$是乘法幺元?是的
    • 乘法关于加法有分配率吗?不是
      • 四舍五入的溢出和不精确性
      • $1 e 20 \star(1 e 20-1 e 20)=0.0,1 e 20 1 e 20-1 e 20 1 e 20=\mathrm{NaN}$
  • 单调性
    • $a\ge b\Rightarrow a+c\ge b+c$?几乎成立
      • 除了无穷大和NaN

浮点数加法

  • 考虑$(-1)^{s_1} M_1 2^{E_1}+(-1)^{s_2} M_2 2^{E_2}$,假设$E_1>E_2$
  • 精确结果:$(-1)^sM2^E$
    • 符号位$s$,尾数$M$:对齐加法的结果
    • 阶码$E$:$E_1$
  • 修正
    • 如果$M\ge 2$,右移$M$,增加$E$
    • 如果$M<1$,左移$M$ $k$个位置,让$E$增加$k$
    • 如果$E$超过范围,则溢出
    • 舍入$M$以满足frac的精度

浮点数加法的数学性质

  • 与阿贝尔群比较
    • 在加法运算下封闭?是的
      • 但可能会产生无穷大或NaN
    • 可交换的?是的
    • 可结合? 不是
      • 四舍五入的溢出和不精确性
      • $(3.14+1e10)-1e10 = 0, 3.14+(1e10-1e10) = 3.14$
    • $0$是加法幺元?是的
    • 每个元素都有加法逆吗? 除了无穷大和NaN
  • 单调性
    • $a\ge b\Rightarrow a+c\ge b+c$?几乎成立
      • 除了无穷大和NaN

C中浮点数

  • C中有两种精度的浮点数
    • float:单精度
    • double:双精度
  • int,float,double进行转换时,程序改变比特的模式如下
    • double/float转换为int
      • 截断分数部分
      • 向$0$舍入
      • 如果超过NaN范围则没有定义:通常转换为$\text{TMin}$
      • 例如$1.999$转换为$1$,$-1.999$转换为$-1$,$1e10$转换为$-21483648$
    • int/float转换为double
      • 因为double的范围更大,所以保留精确值
    • int转换为float
      • 数字不会溢出,但是可能会产生舍入(float的frac域没有足够的位表示int)
    • double转换成float,可能溢出为$+\infty$或$-\infty$,由于精度的问题还会产生舍入

总结

  • IEEE浮点具有明确的数学性质
  • 用$(-1)^s\times M\times 2^E$表示数
  • 与实数运算不同
    • 违反结合律/分布率
    • 给编译器和数值应用程序带来麻烦

习题

int x =;
float f =;
double d =;

假设d,f不是NaN。

1.

False,因为转换成float会产生舍入。

2.

True,double表示的范围更大。

3.

True,double表示的范围更大。

4.

False,产生溢出或舍入。

5.

True,因为只改变了符号位。

6.

False

7.

True

8.

True,因为单调性

9.

True

10.

False,因为不满足结合律